/*
 * @file iso9660.h
 *
 *  Application interface to ISO9660 filesystem.
 *
 */

#ifndef __ISO9660_H_
#define __ISO9660_H_

#include <stdlib.h>

#include <rtems.h>
#include <rtems/libio_.h>

#include "iso9660fs.h"
#include "iso9660_dbg.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct iso9660_cache_s {
  rtems_bdbuf_buffer        *buffer;
  uint32_t                   block;
} iso9660_cache_t;

typedef struct iso9660_volume_info_s {
  char                      *system_identifier;
  char                      *volume_identifier;
  uint16_t                   space_size;
  uint16_t                   set_size;
  uint16_t                   sequence_num;
  uint16_t                   logical_block_size;
  uint16_t                   path_table_size;
  uint16_t                   l_path_table;
  uint16_t                   l_path_table_2;
  uint16_t                   m_path_table;
  uint16_t                   m_path_table_2;
  iso9660_sector_t           root_record_location;
} iso9660_volume_info_t;


typedef enum {
  ISO9660_VOLUME_TYPE_NONE = 0,
  ISO9660_VOLUME_TYPE_BLOCK,
  ISO9660_VOLUME_TYPE_REGULAR
} iso9660_volume_type_t;


/**
 *   Available mount options for ISO9660 filesystem.
 * A pointer to this structure could be passed to mount() as data pointer.
 */
typedef struct iso9660_mount_options_s
{
  uint8_t           uid;            /**< Default UID if data not available */
  uint8_t           gid;            /**< Default GID if data not available */
  uint8_t           map;            /**< Filename mapping, default is 'normal' */
  char              iocharset[32];  /**< 8-bit character set used for I/O ops. */
  iso9660_version_t version;        /**< Flags for extension support */
} iso9660_mount_options_t;



/**
 *    Filesystem information structure
 */
typedef struct iso9660_fs_info_s {
  iso9660_volume_type_t                     type;
  rtems_disk_device                        *disk;

  /**
   * dev is the device id of the host block device
   * when mounting ISO from such a device. When mounting
   * a file, dev is the device id of the host filesystem
   * device id.
   */
  dev_t                                     dev;
  iso9660_cache_t                           cache;

  int                                       dd;
  size_t                                    media_size;

  const rtems_filesystem_file_handlers_r  *directory_handlers;
  const rtems_filesystem_file_handlers_r  *file_handlers;
  iso9660_mount_options_t                   mount_options;

  iso9660_volume_info_t                     volume;
  iso9660_version_t                         version;
  iso9660_version_t                         version_mask;

  uint8_t                                   susp_skip;
} iso9660_fs_info_t;


/**
 *   Do not translate ISO9660 filenames.
 *
 * @see iso9660_mount_options_t
 */
#define ISO9660_MOUNT_MAP_DISABLED    0

/**
 *   Filenames version and leading dots will be stripped if needed.
 *
 * @see iso9660_mount_options_t
 */
#define ISO9660_MOUNT_MAP_NORMAL      1

/**
 *   Filenames will be lowercased and version and leading dots will be stripped
 * if needed.
 *
 * @see iso9660_mount_options_t
 */
#define ISO9660_MOUNT_MAP_LOWERCASE   2


/* a set of routines that handle the nodes which are directories */
extern const rtems_filesystem_file_handlers_r  ISO9660_directory_handlers;
extern const rtems_filesystem_file_handlers_r  ISO9660_file_handlers;

extern int
rtems_iso9660_eval_path(
  const char*                       path,
  size_t                             pathlen,
  int                                flags,
  rtems_filesystem_location_info_t  *pathloc
);

extern int
rtems_iso9660_evalformake(
   const char *path,
   rtems_filesystem_location_info_t *pathloc,
   const char **name
);

extern rtems_filesystem_node_types_t
rtems_iso9660_node_type(
  rtems_filesystem_location_info_t *pathloc
);

extern int
rtems_iso9660_freenode(
    rtems_filesystem_location_info_t      *pathloc
);

extern int
rtems_iso9660_initialize(
  rtems_filesystem_mount_table_entry_t    *mt_entry,
  const void                             *data
);

extern int
rtems_iso9660_initialize_support(
  rtems_filesystem_mount_table_entry_t        *temp_mt_entry,
  const rtems_filesystem_operations_table    *op_table,
  const rtems_filesystem_file_handlers_r     *file_handlers,
  const rtems_filesystem_file_handlers_r     *directory_handlers,
  const iso9660_mount_options_t              *mount_options,
  iso9660_version_t                            version
);

extern int
rtems_iso9660_statvfs(
 rtems_filesystem_location_info_t  *loc,
 struct statvfs                    *buf
);

#define ISO9660_MAGIC_ID      0x43443031  /* CD01 -- Abbr. version of the standard CD001 */
#define ISO9660_SECTOR_SIZE   2048

#define MIN(a, b)  (((a) < (b)) ? (a) : (b))

#define rtems_iso9660_device_descriptor(_fs) \
    ((_fs)->dd)

#define rtems_iso9660_volume_is_block(_fs) \
    (rtems_iso9660_volume_type(_fs) == ISO9660_VOLUME_TYPE_BLOCK)

#define rtems_iso9660_volume_is_regular(_fs) \
    (rtems_iso9660_volume_type(_fs) == ISO9660_VOLUME_TYPE_REGULAR)

#define rtems_iso9660_media_size(_fs) \
    (rtems_iso9660_volume_is_block(_fs)?(_fs)->disk->media_size:(_fs)->media_size)

#define rtems_iso9660_device(_fs) \
    ((_fs)->dev)

#define rtems_iso9660_block_size(_fs) \
    (rtems_iso9660_volume_is_block(_fs)?(_fs)->disk->block_size:1)

#define rtems_iso9660_volume_type(_fs) \
  ((_fs)->type)

#define rtems_iso9660_get_fsinfo_pathloc(_loc) \
  ((iso9660_fs_info_t*) ((_loc)->mt_entry->fs_info))

#define rtems_iso9660_get_record_pathloc(_loc) \
  ((iso9660_record_t*) ((_loc)->node_access))

#define rtems_iso9660_set_record_pathloc(_loc, record) \
  (_loc)->node_access = record

#define rtems_iso9660_get_fsinfo_iop(_iop) \
  ((iso9660_fs_info_t*) ((_iop)->pathinfo.mt_entry->fs_info))

#define rtems_iso9660_get_record_iop(_iop) \
  ((iso9660_record_t*) ((_iop)->pathinfo.node_access))


#ifdef __cplusplus
}
#endif

#endif /* __ISO9660_H_ */
